import java.awt.EventQueue;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.JTextArea;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.control.Control;
import org.parosproxy.paros.core.proxy.ProxyListener;
import org.parosproxy.paros.model.Model;
import org.parosproxy.paros.network.HttpHeader;
import org.parosproxy.paros.network.HttpMalformedHeaderException;
import org.parosproxy.paros.network.HttpMessage;
import org.parosproxy.paros.network.HttpSender;
import org.parosproxy.paros.network.SSLConnector;

import com.bluestone.extension.paros.ProxyServer;
import com.bluestone.scripts.ActionScript;
import com.bluestone.scripts.Command;
import com.bluestone.scripts.TestCase;
import com.bluestone.scripts.TestSuite;

/**
 * CallFuntionAction can execute a function.
 * @author <a href="mailto:bluesotne.master@gmail.com">daniel.q</a>
 */
public class PlayDataTool extends Thread {

	public static void main(String[] args) {
		try {

			String file = "playdata_scripts.xml";
			File input = new File(file);
			JAXBContext context = JAXBContext.newInstance(TestSuite.class);
			Unmarshaller unmarshaller = context.createUnmarshaller();
			TestSuite testsuite = (TestSuite) unmarshaller.unmarshal(input);
			List<TestCase> testcases = testsuite.getTestcases();
			for (TestCase testcase : testcases) {
				List<Command> commands = testcase.getCommands();
				for (Command command : commands) {
					List<ActionScript> actions = command.getActions();
					for (ActionScript action : actions) {
						if (!new PlayDataTool().execute(action)) {
							break;
						}
						;
					}
				}
			}

		} catch (Exception me) {
			me.printStackTrace();
		}
	}

	ActionScript action = null;
	String outputfolder = "";
	String recordfile = "";
	HttpSender httpSender = null;
	Hashtable<String, Record> recordMsgs = new Hashtable<String, Record>();
	Hashtable<String, Record> playMsgs = new Hashtable<String, Record>();
	
	Vector<PlayListener> listeners = new Vector<PlayListener>();


	public void addRecordListener(PlayListener tenlistenerer) {
		listeners.add(tenlistenerer);
	}

	public void removeRecordListener(PlayListener listener) {
		listeners.remove(listener);
	}

	long activetime = System.currentTimeMillis();

	/**
	 * This action can execute a query.
	 * @return false 
	 */

	public boolean execute(ActionScript action) {
		this.action = action;

		//start proxy server
		ProxyServer proxyServer = ProxyServer.getProxyServer();
		proxyServer.run(action);

		//clear output folder
		String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
		outputfolder = action.getPara("outputfolder");
		if (outputfolder == null || outputfolder.length() == 0) {
			outputfolder = ".\\play";
		}
		outputfolder = outputfolder + "\\" + date + "\\";

		File folder = new File(outputfolder);
		Util.deleteDirectory(folder);
		mkdirs(outputfolder);

		String recordFolder = action.getPara("recordfolder");
		if (recordFolder == null || recordFolder.length() == 0) {
			recordFolder = ".\\record\\" + date + "\\";
		}
		
		//load play listener
		String playListeners = action.getPara("playlistener");
		if(playListeners!=null && playListeners.length()>0){
			java.util.StringTokenizer tokens = new java.util.StringTokenizer(playListeners,",");
			while(tokens.hasMoreTokens()){
				String className = tokens.nextToken();
				try {
					Object obj = Class.forName(className).newInstance();
					if(PlayListener.class.isInstance(obj)){
						this.addRecordListener((PlayListener) obj);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				
			}
		}
		
		String recordFile = recordFolder + "record.txt";
		List<String> records = Util.getListdata(recordFile);
		for (String id : records) {
			Record record = new Record(id, recordFolder);
			Record play = record.clone();
			recordMsgs.put(id, record);
			playMsgs.put(id, play);
		}

		//play record
		String playfile = outputfolder + "play.txt";
		StringBuffer plays = new StringBuffer();
		for (String id : records) {
			String key = id;
			Record r = playMsgs.get(key);
			beforePlay(r);
			play(r);
			afterPlay(r);
			plays.append(""+r.getId()).append("\r\n");
			Util.saveHttpMessage(r.getHttpMessage(), outputfolder, r.getId());				
			Util.createFile(playfile, plays.toString().getBytes());
		}

		getHttpSender().shutdown();

		return true;
	}

	private void play(final Record r) {

		try {
			getHttpSender().sendAndReceive(r.getHttpMessage(), false);

			EventQueue.invokeAndWait(new Runnable() {
				public void run() {
					if (!r.getHttpMessage().getResponseHeader().isEmpty()) {

					}
				}
			});
		} catch (Exception me) {
			me.printStackTrace();
		}

	}

	private void beforePlay(Record r) {
		for (PlayListener listener : listeners) {
			boolean flag = listener.beforePlay(r, recordMsgs);
			if (flag) {
				break;
			}
		}
	}

	private void afterPlay(Record r) {
		for (PlayListener listener : listeners) {
			boolean flag = listener.afterPlay(r, recordMsgs);
			if (flag) {
				break;
			}
		}
	}

	private HttpSender getHttpSender() {

		if (httpSender == null) {
			ProtocolSocketFactory sslFactory = null;
			try {
				Protocol protocol = Protocol.getProtocol("https");
				sslFactory = protocol.getSocketFactory();
			} catch (Exception e) {
			}
			if (sslFactory == null || !(sslFactory instanceof SSLConnector)) {
				Protocol.registerProtocol("https", new Protocol("https",
						(ProtocolSocketFactory) new SSLConnector(), 443));
			}
			try {
				Model.getSingleton().getOptionsParam().load(
						Constant.getInstance().FILE_CONFIG);
			} catch (Exception e) {
				e.printStackTrace();
			}

			httpSender = new HttpSender(Model.getSingleton().getOptionsParam()
					.getConnectionParam(), true);
		}
		return httpSender;
	}

	synchronized private boolean mkdirs(String path) {
		boolean flag = true;
		File file = new File(path);
		if (!file.exists()) {
			flag = file.mkdirs();
		}
		return flag;
	}




}


